﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Web;
using System.Xml.Serialization;
using Cos.Core.Service;
using Cos.Module.CMS;
using Cos.Module.Configuration;
using Cos.Module.Template;

namespace Alogient.Cameleon.Sdk.Items
{
    [Serializable]
    [XmlRoot("Element")]
    public class CMElement
    {
        protected CMElement()
        {
            
        }

        public CMElement(int navID, string cultureCode, string name)
        {
            var pageService = ServiceLocator.Get<IPageService>();
            var cultureService = ServiceLocator.Get<ICultureService>();
            
            this.LoadElement(pageService.GetElement(cultureService.GetCulture(cultureCode), navID, name));
        }
        
        internal CMElement(Cos.Core.Model.Content.Element element)
        {
            this.LoadElement(element);
        }

        protected void LoadElement(Cos.Core.Model.Content.Element element)
        {
            var pageService = ServiceLocator.Get<IPageService>();
            var page = pageService.GetPage(element.PageId);
            this.navId = page.NavId;
            this.cultureCode = page.CultureCode;

            var templateService = ServiceLocator.Get<ITemplateService>();
            var part = templateService.GetPart(element.PartId);
            var dataType = templateService.GetDataType(part.DataTypeId);

            this.elementId = element.ElementId;
            this.elementName = part.PartName;
            this.PartID = element.PartId;
            this.dataTypeName = dataType.Name;
            this.Value = CMServices.IsLive ? element.Value : element.PreviewValue;
            this.File = CMServices.IsLive ? element.File : element.PreviewFile;
        }

        #region Accessors

        [XmlAttribute]
        public int ElementID
        {
            get { return this.elementId; }
            set { }
        }
        protected int elementId;
        
        [XmlAttribute]
        public int NavID
        {
            get { return this.navId; }
            set { }
        }
        protected int navId;
        
        [XmlAttribute]
        public string CultureCode
        {
            get { return this.cultureCode; }
            set { }
        }
        protected string cultureCode;

        [XmlIgnore]
        public int PartID { get; internal set; }

        [XmlAttribute]
        public string ElementName
        {
            get { return this.elementName; }
            set { }
        }
        protected string elementName;
        
        [XmlAttribute]
        public string DatatypeName
        {
            get { return this.dataTypeName; }
            set { }
        }
        protected string dataTypeName;
        
        [XmlAttribute]
        public string OriginalMediaFile
        {
            get { return this.GetImageFile(ImageFileType.Original); }
            set { }
        }
        
        [XmlAttribute]
        public string PresentationImageFile
        {
            get { return this.GetImageFile(ImageFileType.Presentation); }
            set { }
        }
        protected string presentationImageFile;
        
        [XmlAttribute]
        public string ThumbnailImageFile
        {
            get { return this.GetImageFile(ImageFileType.Thumbnail); }
            set { }
        }
        protected string thumbnailImageFile;

        [XmlAttribute]
        public string ImageAltText 
        { 
            get
            {
                return (this.DatatypeName == "Image") ? this.Value : string.Empty;
            }
            set { }
        }

        [XmlText]
        public string TextValue 
        {
            get
            {
                return (this.DatatypeName != "Media" && this.DatatypeName != "Image") ? this.Value : string.Empty;
            }
            set { }
        }
        
        [XmlIgnore]
        public string Value { get; internal set; }
        
        [XmlIgnore]
        public string File { get; internal set; }
        
        #endregion

        /// <summary>
        /// String value
        /// </summary>
        /// <returns>string value</returns>
        public override string ToString()
        {
            return this.Value;
        }

         /// <summary>
        /// Returns the path to the element media file
        /// </summary>
        /// <returns>Path to the media</returns>
        public string GetMediaFile()
        {
            if (this.DatatypeName != "Media" && this.DatatypeName != "Image")
            {
                throw new CMException(String.Format("Cannot get Media File - Element is not a media [NavID={0}, CultureCode={1}, ElementName={2}]", this.NavID, this.CultureCode, this.ElementName));
            }

            var folderUrl = CMSettings.AdminUrl;

            if (HttpContext.Current != null && HttpContext.Current.Request.IsSecureConnection)
            {
                folderUrl = CMSettings.HttpsAdminUrl;
            }

            return String.Format(Constants.GetMediaFileFormat(), folderUrl + "/Media/", this.NavID, this.ElementID, this.CultureCode, this.File);
        }

        /// <summary>
        /// Returns the alternative text for an image element.
        /// </summary>
        /// <returns>Alt text</returns>
        public string GetImageAltText()
        {
            return this.Value;
        }

        /// <summary>
        /// Returns the path to the element image file in the original size
        /// </summary>
        /// <returns>Path to the image</returns>
        public string GetImageFile()
        {
            return this.GetImageFile(ImageFileType.Original);
        }

        /// <summary>
        /// The original image width
        /// </summary>
        /// <returns>Width</returns>
        public int GetImageWidth()
        {
            return this.GetImageWidth(ImageFileType.Original);
        }

        /// <summary>
        /// The image width for the defined size
        /// </summary>
        /// <param name="imageFileType">Image format</param>
        /// <returns>Width</returns>
        public int GetImageWidth(ImageFileType imageFileType)
        {
            if (HttpContext.Current != null && !string.IsNullOrEmpty(HttpContext.Current.Request.ApplicationPath))
            {
                var image = this.GetImage(imageFileType);
                if (image != null)
                {
                    return image.Width;
                }
            }

            return 0;
        }

        /// <summary>
        /// The original image height
        /// </summary>
        /// <returns>Height</returns>
        public int GetImageHeight()
        {
            return this.GetImageHeight(ImageFileType.Original);
        }

        /// <summary>
        /// The image height for the defined size
        /// </summary>
        /// <param name="imageFileType">Image format</param>
        /// <returns>Height</returns>
        public int GetImageHeight(ImageFileType imageFileType)
        {
            if (HttpContext.Current != null && !string.IsNullOrEmpty(HttpContext.Current.Request.ApplicationPath))
            {
                var image = this.GetImage(imageFileType);
                if (image != null)
                {
                    return image.Height;
                }
            }

            return 0;
        }

        /// <summary>
        /// The image path for the defined size
        /// </summary>
        /// <param name="imageFileType">Image format</param>
        /// <returns>Path to the image</returns>
        public string GetImageFile(ImageFileType imageFileType)
        {
            if (this.DatatypeName != "Image" && this.DatatypeName != "Media")
            {
                throw new CMException(String.Format("Cannot get Media File - Element is not an image [NavID={0}, CultureCode={1}, ElementName={2}]", this.NavID, this.CultureCode, this.ElementName));
            }

            if (this.DatatypeName == "Media" && imageFileType != ImageFileType.Original)
            {
                throw new CMException("Cannot get Media File - Wrong file format");
            }

            var folderUrl = CMSettings.AdminUrl;

            if (HttpContext.Current != null && HttpContext.Current.Request.IsSecureConnection)
            {
                folderUrl = CMSettings.HttpsAdminUrl;
            }

            return String.Format(Constants.GetFileFormat(), folderUrl + "/Media/", this.NavID, this.PartID, this.CultureCode, ImageFileTypeHelper.GetImageFileTypeCode(imageFileType), this.File);
        }

        private System.Drawing.Image GetImage(ImageFileType imageFileType)
        {
            var imageFile = this.GetImageFilePath(imageFileType);

            try
            {
                if (!System.IO.File.Exists(imageFile))
                {
                    return null;
                }

                return System.Drawing.Image.FromFile(imageFile);
            }
            catch (Exception ex)
            {
                var exception = new CMException(String.Format("Cannot get Image File - The image is not accesible [NavID={0}, CultureCode={1}, ElementName={2}, AdminURL={3}]", this.NavID, this.CultureCode, this.ElementName, CMSettings.AdminUrl), ex);

                throw exception;
            }
        }

        private string GetImageFilePath(ImageFileType imageFileType)
        {
            if (this.DatatypeName != "Image")
            {
                throw new CMException(String.Format("Cannot get Image File - Element is not an image [NavID={0}, CultureCode={1}, ElementName={2}]", this.NavID, this.CultureCode, this.ElementName));
            }

            var imageFile = HttpContext.Current.Server.MapPath(String.Format(Constants.GetFileFormat(), CMSettings.MediaUrl, this.NavID, this.ElementID, this.CultureCode, ImageFileTypeHelper.GetImageFileTypeCode(imageFileType), this.File));

            return imageFile;
        }
    }
}
